/*
 * envelope.c
 *
 * 		Amplitude envelope implementation.
 *
 * 		Amplitude range:
 * 		Attack section: 	0.0 - 1.0
 * 		Decay section:		1.0 - 0.7
 * 		Sustain section:	0.7
 * 		Release section:	0.7 - 0.0
 *
 */

#include <envelope.h>

// global variables
static int32_t envAttackSampleTime;		// attack sample time
static int32_t envDecaySampleTime;		// decay sample time
static int32_t envReleaseSampleTime;	// release sample time

static float envAttackInc;				// attack increment value
static float envDecayInc;				// decay increment value
static float envReleaseInc;				// release increment value

static int32_t envSection;				// current envelope section
static float envVal;					// current amplitude
static int32_t count;					// sample counter

/****************************************************************************
* DESCRIPTION: Initialise the amplitude envelope
* RETURN:      none
*****************************************************************************/
void envelope_init(float attackTime, float decayTime, float releaseTime) {

	// calculate sample times for each section
	envAttackSampleTime  = attackTime * sampleRate;
	envDecaySampleTime 	 = decayTime * sampleRate;
	envReleaseSampleTime = releaseTime * sampleRate;

	// calculate increments for each section
	envAttackInc 	= 1.0 / envAttackSampleTime;
	envDecayInc		= 0.3 / envDecaySampleTime;
	envReleaseInc 	= 0.7 / envReleaseSampleTime;

	// set initial section
	envSection = ATTACK;

	// initial amplitude value
	envVal = 0;

	// init counter
	count = 0;
}

/****************************************************************************
* DESCRIPTION: Update the envelope
* RETURN:      int32_t new sample value
*****************************************************************************/
int32_t envelope_update(int32_t sampleIn) {

	// if envelope is in attack section
	if(envSection == ATTACK){

		// multiply sample by new amplitude value
		sampleIn *= envVal;

		// increment envelope amplitude value
		envVal += envAttackInc;

		// check if this section is complete
		count++;
		if(count == envAttackSampleTime) {
			count = 0;
			envSection = DECAY;
		}
	}
	// if envelope is in decay section
	else if(envSection == DECAY) {

		// multiply sample by new amplitude value
		sampleIn *= envVal;

		// increment envelope amplitude value
		envVal -= envDecayInc;

		// check if this section is complete
		count++;
		if(count == envDecaySampleTime) {
			count = 0;
			envSection = SUSTAIN;
		}
	}
	// if envelope is in sustain section
	else if(envSection == SUSTAIN) {

		// multiply sample by new amplitude value
		sampleIn *= envVal;
	}
	// if envelope is in release section
	else if(envSection == RELEASE) {

		// multiply sample by new amplitude value
		sampleIn *= envVal;

		// increment envelope amplitude value
		envVal -= envReleaseInc;

		// check if this section is complete
		if(envVal <= 0) {
			// turn off voice
			voice_off();
		}
	}
	// return new sample
	return sampleIn;
}

/****************************************************************************
* DESCRIPTION: Set envelope section to release
* RETURN:      none
*****************************************************************************/
void envelope_release() {
	envSection = RELEASE;
}
